﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.CodeAnalysis;

namespace SPStyleCop
{
    /// <summary>
    /// ServiceLocator class to serve location of the implementation of type T.
    /// </summary>
    public sealed class ServiceLocator
    {
        #region Fields

        private static ServiceLocator _instance;

        private readonly IDictionary<Type, object> _services;

        #endregion

        #region Constructor
        /// <summary>
        /// Initialize a new instance of the <see cref="ServiceLocator"/> class.
        /// </summary>
        private ServiceLocator()
        {
            this._services = new Dictionary<Type, object>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the service of the given type.
        /// </summary>
        /// <typeparam name="T">The service type.</typeparam>
        /// <returns>The service.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "API designed for type reference")]
        public static T GetService<T>()
        {
            return ServiceLocator.GetInstance().InternalGetService<T>();
        }

        /// <summary>
        /// Registers the service.
        /// </summary>
        /// <typeparam name="T">The service type.</typeparam>
        /// <param name="service">The service.</param>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "API designed for type reference")]
        public static void RegisterService<T>(object service)
        {
            ServiceLocator.GetInstance().InternalRegisterService<T>(service);
        }

        private T InternalGetService<T>()
        {
            object result;

            this._services.TryGetValue(typeof(T), out result);

            return (T)result;
        }

        private void InternalRegisterService<T>(object service)
        {
            this._services.Add(typeof(T), service);
        }

        private static ServiceLocator GetInstance()
        {
            if (ServiceLocator._instance == null)
            {
                ServiceLocator._instance = new ServiceLocator();
            }

            return ServiceLocator._instance;
        }

        #endregion
    }
}
